package net.gianrishandy.jbase.component;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;

import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;

import net.gianrishandy.jbase.component.adapter.DataGridAdapter;
import net.gianrishandy.jbase.component.event.DataGridEvent;
import net.gianrishandy.jbase.component.interfaces.DataGridType;
import net.gianrishandy.jbase.component.listener.DataGridListener;
import net.gianrishandy.jbase.component.listener.LookupCellListener;
import net.gianrishandy.jbase.component.support.DataGridProperty;
import net.gianrishandy.jbase.component.support.LookupCell;
import net.gianrishandy.jbase.model.DataColumn;
import net.gianrishandy.jbase.model.DataTable;

import com.toedter.calendar.JDateChooserCellEditor;

/**
 * @author Gian Rishandy
 *
 */
public class DataGrid extends JTable implements DataGridType{
	
	private static final long serialVersionUID = 556950511468825591L;
	
	private DataTable dataTable;
	private DataGridProperty dataGridProperty;
	private Integer dataGridType;
	
	public DataGrid() {
		dataGridType = DataGrid.Transaction;
	}
	
	/**
	 * Repaint DataGrid component
	 */
	public void rebind(){
		if(dataTable != null){
			if(dataGridProperty != null){
				if(dataGridProperty.getDisableColumns() != null){
					dataTable.setDisableColumns(dataGridProperty.getDisableColumns());
				}
			}
			
			dataTable.setDataTableType(dataGridType);
			dataTable.addTableModelListener(new TableModelListener() {
				@Override
				public void tableChanged(TableModelEvent e) {
					if(e.getType() == TableModelEvent.INSERT){
						dataGridAfterRowInserted(e);
					}else if(e.getType() == TableModelEvent.UPDATE){
						dataGridAfterColUpdated(e);
					}else if(e.getType() == TableModelEvent.DELETE){
						dataGridAfterRowDeleted(e);
					}
				}
			});
			
			setModel(dataTable);
			repaintTable();
			settingDataGrid();
			
			if(getComponentPopupMenu() != null){
				getComponentPopupMenu().removeAll();
			}
			
			if(dataGridType == DataGrid.Transaction){
				setColumnSelectionAllowed(true);
				setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
				setComponentPopupMenu(menuGrid());
				
				if(dataTable.getRowCount() == 0){
					dataTable.addRow();
				}
			}else{
				setColumnSelectionAllowed(false);
				setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
			}
		}
	}
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private void repaintTable(){
		
		for(int i=0;i<getColumnCount();i++){
			DataColumn datacolumn = dataTable.getColumn(i);
			if(datacolumn.getColumnClass() == Date.class){
				getColumnModel().getColumn(i).setCellEditor(new JDateChooserCellEditor());
			}
			
			if(dataGridProperty != null){
				if(dataGridProperty.getComboColumns() != null){
					Hashtable<String, Object[]> combo = dataGridProperty.getComboColumns();
					for(Enumeration<String> en = combo.keys(); en.hasMoreElements();){
						String key = en.nextElement();
						Object[] value = combo.get(key);
						
						if(datacolumn.getColumnName().equalsIgnoreCase(key)){
							JComboBox combobox = new JComboBox(value);
							getColumnModel().getColumn(i).setCellEditor(new DefaultCellEditor(combobox));
						}
					}
				}				
				
				if(dataGridProperty.getLookupColumns() != null){
					String[] lookup = dataGridProperty.getLookupColumns();
					for(int ii=0;ii<lookup.length;ii++){
						final String columnName = lookup[ii];
						if(columnName.equalsIgnoreCase(datacolumn.getColumnName())){
							
							LookupCell cell = new LookupCell();
							cell.addLookupCellListener(new LookupCellListener() {
								@Override
								public void lookupCellActionPerformed() {
									DataGridEvent event = new DataGridEvent(this);
									event.setColumnName(columnName);
									event.setColumnIndex(getSelectedColumn());
									event.setRowIndex(getSelectedRow());
									
									dataGridLookupActionPerformed(event);
									
									getColumnModel().getColumn(getSelectedColumn()).getCellEditor().cancelCellEditing();
									requestFocus();
								}
							});
							getColumnModel().getColumn(i).setCellEditor(new DefaultCellEditor(cell));
						}
					}
				}
			}
		}		
			
		if(dataGridProperty != null){
			if(dataGridProperty.getInvisibleColumns() != null){
				String[] invis = dataGridProperty.getInvisibleColumns();
				for(int i=0;i<invis.length;i++){
					String columnName = invis[i];
					for(int ii=0;ii<getColumnCount();ii++){
						String colName = getColumnName(ii);
						if(colName.equalsIgnoreCase(columnName)){
							removeColumn(getColumnModel().getColumn(ii));
							break;
						}
					}
				}
			}
		}
			
	}
	
	private void settingDataGrid(){
		if(dataGridProperty != null){
			if(dataGridProperty.getColumnSize() != null){
				Hashtable<String, Integer> size = dataGridProperty.getColumnSize();
				
				for(Enumeration<String> en=size.keys(); en.hasMoreElements();){
					String key = en.nextElement();
					Integer value = size.get(key);
					
					getColumnModel().getColumn(getColumnIndex(key)).setPreferredWidth(value);
				}
			}
			
			if(dataGridProperty.getColumnTitle() != null){
				Hashtable<String, String> title = dataGridProperty.getColumnTitle();
				
				for(Enumeration<String> en=title.keys(); en.hasMoreElements();){
					String key = en.nextElement();
					String value = title.get(key);
					
					getColumnModel().getColumn(getColumnIndex(key)).setHeaderValue(value);
				}
			}
		}
	}
	
	/**
	 * Get column name index
	 * 
	 * @param columnName
	 * @return Integer
	 */
	public int getColumnIndex(String columnName){
		for(int i=0;i<getColumnCount();i++){
			if(columnName.equalsIgnoreCase(getColumnName(i))){
				return i;
			}
		}
		return -1;
	}
	
	private JPopupMenu menuGrid(){
		if(dataTable != null){
			JMenuItem addItem = new JMenuItem("Add Row");
			addItem.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent evt) {
					dataTable.addRow();
				}
			});
			
			JMenuItem removeItem = new JMenuItem("Remove Row");
			removeItem.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent evt) {
					int selectedRow = getSelectedRow();
					if(selectedRow > -1 || getRowCount() > 1){
						dataTable.removeRow(selectedRow);
					}
				}
			});
			
			JPopupMenu menu = new JPopupMenu();
			menu.add(addItem);
			menu.add(removeItem);
			
			return menu;
		}else{
			JOptionPane.showMessageDialog(null, "DataTable Must Not Be Empty");
			return null;
		}
		
	}
	
	public void addDataGridListener(DataGridAdapter listener){
		listenerList.add(DataGridListener.class, listener);
	}
	
	public void removeDataGridListener(DataGridAdapter listener){
		listenerList.remove(DataGridListener.class, listener);
	}
	
	private void dataGridAfterRowInserted(TableModelEvent evt){
		Object[] list = listenerList.getListenerList();
		for(int i=0;i<list.length;i+=2){
			if(list[i] == DataGridListener.class){
				((DataGridListener)list[i+1]).afterRowInserted(evt);
			}
		}
	}
	
	private void dataGridAfterRowDeleted(TableModelEvent evt){
		Object[] list = listenerList.getListenerList();
		for(int i=0;i<list.length;i+=2){
			if(list[i] == DataGridListener.class){
				((DataGridListener)list[i+1]).afterRowDeleted(evt);
			}
		}
	}
	
	private void dataGridAfterColUpdated(TableModelEvent evt){
		Object[] list = listenerList.getListenerList();
		for(int i=0;i<list.length;i+=2){
			if(list[i] == DataGridListener.class){
				((DataGridListener)list[i+1]).afterColUpdated(evt);
			}
		}
	}
	
	private void dataGridLookupActionPerformed(DataGridEvent evt){
		Object[] list = listenerList.getListenerList();
		for(int i=0;i<list.length;i+=2){
			if(list[i] == DataGridListener.class){
				((DataGridListener)list[i+1]).dataGridLookupActionPerformed(evt);
			}
		}
	}
	
	public DataTable getDataTable() {
		return dataTable;
	}

	public void setDataTable(DataTable dataTable) {
		this.dataTable = dataTable;
	}

	public DataGridProperty getDataGridProperty() {
		return dataGridProperty;
	}

	public void setDataGridProperty(DataGridProperty dataGridProperty) {
		this.dataGridProperty = dataGridProperty;
	}

	public Integer getDataGridType() {
		return dataGridType;
	}

	public void setDataGridType(Integer dataGridType) {
		this.dataGridType = dataGridType;
	}
}
